<?php
/**
 * RedCross Application
 *
 * @copyright Copyright (c) 2010, Kristian Stokke Tryggestad, Rune Vikestad, Andreas Flaten Wist, Simen Nicolai Echholt, Ole Henrik Jahren
 */

/**
 * Factory class for instantiating services
 *
 * @package RedCross
 * @category RedCross
 */
class RedCross_Factory
{
    /**
     * A singleton instance of this class
     * @var $_instance RedCross_Factory
     */
    private static $_instance;

    /**
     * Array of cached services
     * @var array
     */
    private $services = array();

    private $_acl;

    /**
     * Private construction class
     * Creates a new instance of the class if it is not already instantiated
     */
    private static function construct()
    {
    	if (self::$_instance == null) {
    		self::$_instance = new self();
    	}
    }

    /**
     * Retrieves a service
     * The service name should be on the form:
     * Core_Service_User
     * @param string $serviceName
     */
    public static function getService($serviceName)
    {
        self::construct();
        return self::$_instance->retrieveService($serviceName);
    }

    /**
     * (non-PHPdoc)
     * @see library/RedCross/Factory#attachService($service)
     * @param RedCross_Service_ServiceInterface $serviceName
     */
    public static function addService(RedCross_Service_ServiceInterface $serviceName)
    {
        self::construct();
        return self::$_instance->attachService($serviceName);
    }

    public static function setRole(RedCross_Acl $acl)
    {
        self::construct();
        foreach (self::$_instance->getServices() as $service) {
        	if ($service instanceof RedCross_Service_ServiceAbstract) {
        		$service->setRole($acl->retrieveRole());
        	}
        }
    }

    /**
     * Private constructor
     */
    private function __construct()
    {}

    /**
     * Method for attaching a new service
     * @param RedCross_Service_ServiceInterface $service
     */
    public function attachService(RedCross_Service_ServiceInterface $service)
    {
        $serviceName = get_class($service);
        // Inject the ACL
        if ($service instanceof RedCross_Service_ServiceAbstract) {
        	$this->_injectAcl($service);
        }
        $this->services[$serviceName] = $service;
    }

    /**
     * Attempts to retrieve a named service either by instantiating it,
     * or by retrieving it from the 'cache'
     *
     * @param $serviceName
     * @return RedCross_Service_ServiceAbstract
     */
    public function retrieveService($serviceName)
    {
        $serviceName = (string) $serviceName;
        if (!isset($this->services[$serviceName])) {
        	// Check if there exists a method for loading the service
        	$methodName = 'get' . str_replace('_', '', $serviceName);
            if (in_array($methodName, get_class_methods($this))) {
            	$this->attachService($this->$methodName());
            	return $this->services[$serviceName];
            }
            //If no function for loading the service is explicitly defined,
            //try doing it the default way
         	$gatewayName = explode('_', $serviceName);
         	if (count($gatewayName) >= 3)
         	{
         		$gatewayName = $gatewayName[0] . '_Gateway_' . $gatewayName[2];
	            $gateway = new $gatewayName();
	            $service = new $serviceName($gateway);
	            $this->attachService($service);
	            return $this->services[$serviceName];
         	}

            // If not, try to instantiate the service
            $this->attachService(new $serviceName());
        }
        return $this->services[$serviceName];
    }

    public function getServices()
    {
        return $this->services;
    }

    protected function _injectAcl(RedCross_Service_ServiceAbstract $service)
    {
        if (!isset($this->_acl)) {
            $bootstrap = Zend_Controller_Front::getInstance()->getParam('bootstrap');
            $this->_acl = $bootstrap->getResource('Acl');
        }
        $service->setAcl($this->_acl);
		$service->setRole($this->_acl->retrieveRole());
    }

    public function getCoreServiceAuth()
    {
        $auth = Zend_Auth::getInstance();
        $adapter = new RedCross_Auth_Doctrine_Adapter();
        return new Core_Service_Auth($auth, $adapter);
    }

    public function getCoreServicePasswordReset()
    {
        $gateway = new Core_Gateway_PasswordReset();
        $userGateway = new Core_Gateway_User();
        $mailer = new Zend_Mail('utf-8');
        return new Core_Service_PasswordReset($gateway, $userGateway, $mailer);
    }
}